package com.zmn.oms.business.impl.perf;

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.zmn.common.constant.GlobalConsts;
import com.zmn.common.dictionary.GlobalDict;
import com.zmn.common.utils.date.DateUtil;
import com.zmn.common.utils.math.MathUtil;
import com.zmn.common.utils.math.MoneyUtil;
import com.zmn.common.utils.number.NumberUtil;
import com.zmn.common.utils.office.excel.ExportExcelBuilder;
import com.zmn.oms.business.interfaces.es.OrderWorkEsBService;
import com.zmn.oms.business.interfaces.perf.PerfCityBService;
import com.zmn.oms.common.constant.OrderConsts;
import com.zmn.oms.common.constant.OrderStatusConsts;
import com.zmn.oms.model.entity.perf.PerfCity;
import com.zmn.oms.model.entity.perf.PerfCityQuery;
import com.zmn.oms.model.entity.perf.PerfCitySummary;
import com.zmn.oms.model.vo.perf.PerfCityVO;
import com.zmn.oms.services.interfaces.perf.PerfCityService;
import org.apache.commons.collections4.ListUtils;
import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.ss.util.CellRangeAddress;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.script.Script;
import org.elasticsearch.script.ScriptType;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.aggregations.Aggregation;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.Aggregations;
import org.elasticsearch.search.aggregations.bucket.filter.ParsedFilter;
import org.elasticsearch.search.aggregations.bucket.terms.ParsedStringTerms;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.aggregations.metrics.ParsedSum;
import org.elasticsearch.search.aggregations.metrics.ParsedTopHits;
import org.springframework.data.domain.Pageable;
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

import static com.zmn.common.constant.GlobalConsts.PLAT_MARK_ZMN;
import static com.zmn.common.dictionary.GlobalDict.OPERATOR_TYPE_ADMIN;
import static com.zmn.pay.common.constant.PayConsts.PAY_CHANNEL_PLATFORM_YIPAY;
import static com.zmn.pay.common.constant.PayConsts.PAY_TYPE_APP;

/**
 * 类描述: 城市绩效
 *
 * @author liuying
 * @date 2019/01/30 4:43 PM
 */
@SuppressWarnings("AlibabaRemoveCommentedCode")
@Service
public class PerfCityBServiceImpl implements PerfCityBService {

    @Resource
    private OrderWorkEsBService orderWorkEsBService;

    @Resource
    private PerfCityService perfCityService;

    /**
     * 描述: 数据基础分组值大小 数组超出该值则 切割为5组进行入库操作
     *
     * @author wangjie
     * @date 10:52 2019/3/25
     **/
    private static final Integer BASE_CROUP_NUM = 2000;

    @Override
    @SuppressWarnings("Duplicates")
    @Transactional(rollbackFor = Exception.class)
    public List<PerfCity> queryStatisticsList(String beginTime, String endTime) {

        int month = Integer.parseInt(DateUtil.toString(beginTime, DateUtil.FORMAT_DEFAULT, DateUtil.FORMAT_MONTH2));
        NativeSearchQuery nativeSearchQuery = new NativeSearchQueryBuilder()
                .withQuery(
                        QueryBuilders.boolQuery()
                                .must(QueryBuilders.termQuery("isDuplicate", false))
                                .must(QueryBuilders.termQuery("plat", PLAT_MARK_ZMN))
                                .must(QueryBuilders.termQuery("platWork", PLAT_MARK_ZMN))
                                .must(QueryBuilders.termsQuery("type", Arrays.asList(OrderConsts.ORDER_TYPE_NEW, OrderConsts.ORDER_TYPE_REWORK)))
                                .must(QueryBuilders.rangeQuery("manageCompanyId").gt(0))
                                .must(
                                        QueryBuilders.boolQuery()
                                                .should(QueryBuilders.rangeQuery("receiveTime").from(beginTime).to(endTime))
                                                .should(QueryBuilders.rangeQuery("accountTime").from(beginTime).to(endTime))
                                )
                )
                .withPageable(Pageable.unpaged())
                .addAggregation(
                        AggregationBuilders.terms("companyId_cityId").script(
                                new Script(ScriptType.INLINE, "painless", "doc['manageCompanyId'].value + '|' + doc['cityId'].value", Maps.newHashMapWithExpectedSize(0))
                        )
                                .size(10000)
                                .subAggregation(
                                        AggregationBuilders.topHits("top").size(1).fetchSource(new String[]{"companyId", "cityId", "companyName", "cityName", "plat", "manageCompanyId", "manageCompanyName"}, new String[0])
                                )
                                .subAggregation(
                                        AggregationBuilders.filter("receiveTimeFilter", QueryBuilders.rangeQuery("receiveTime").from(beginTime).to(endTime))
                                                .subAggregation(
                                                        // 人工弃单：弃单员为后台人员，非系统弃单；指：新单中弃单，不含返修、退款、重复单
                                                        AggregationBuilders.filter(
                                                                "discardCount",
                                                                QueryBuilders.boolQuery()
                                                                        .must(QueryBuilders.termQuery("resulterType", OPERATOR_TYPE_ADMIN))
                                                                        .must(QueryBuilders.termQuery("resultStatus", OrderStatusConsts.WORK_RESULT_DISCARD))
                                                                        .must(QueryBuilders.termQuery("type", OrderConsts.ORDER_TYPE_NEW))
                                                        )
                                                )
                                                .subAggregation(
                                                        // 系统弃单：弃单员为系统，指：新单中的弃单，不含返修、退款、重复单
                                                        AggregationBuilders.filter(
                                                                "sysDiscardCount",
                                                                QueryBuilders.boolQuery()
                                                                        .must(QueryBuilders.termQuery("resulterType", GlobalDict.OPERATOR_TYPE_SYSTEM))
                                                                        .must(QueryBuilders.termQuery("resultStatus", OrderStatusConsts.WORK_RESULT_DISCARD))
                                                                        .must(QueryBuilders.termQuery("type", OrderConsts.ORDER_TYPE_NEW))
                                                        )
                                                )
                                                .subAggregation(
                                                        // 已上门失败：有上门时间，结果：失败；指：新单中的失败，不含返修、退款、重复
                                                        AggregationBuilders.filter(
                                                                "visitFailCount",
                                                                QueryBuilders.boolQuery()
                                                                        .must(QueryBuilders.existsQuery("visitTime"))
                                                                        .must(QueryBuilders.termQuery("resultStatus", OrderStatusConsts.WORK_RESULT_FAIL))
                                                                        .must(QueryBuilders.termQuery("type", OrderConsts.ORDER_TYPE_NEW))
                                                        )
                                                )
                                                .subAggregation(
                                                        // 未上门失败：无上门时间，结果：失败；指新单中的失败，不含返修、退款、重复
                                                        AggregationBuilders.filter("noVisitFailCount",
                                                                QueryBuilders.boolQuery()
                                                                        .mustNot(QueryBuilders.existsQuery("visitTime"))
                                                                        .must(QueryBuilders.termQuery("resultStatus", OrderStatusConsts.WORK_RESULT_FAIL))
                                                                        .must(QueryBuilders.termQuery("type", OrderConsts.ORDER_TYPE_NEW))
                                                        )
                                                )
                                                .subAggregation(
                                                        // 返修单：录入时间的返修单，不含重复
                                                        AggregationBuilders.filter(
                                                                "reworkOrderCount",
                                                                QueryBuilders.termQuery("type", OrderConsts.ORDER_TYPE_REWORK))
                                                )
                                                .subAggregation(
                                                        // 新单：录入时间的返修单，不含重复
                                                        AggregationBuilders.filter(
                                                                "newOrderCount",
                                                                QueryBuilders.termQuery("type", OrderConsts.ORDER_TYPE_NEW)
                                                        )
                                                )
                                                .subAggregation(
                                                        // 返修成功：录入时间的返修单，有完成时间，（订单收入）>= 50，不含重复
                                                        AggregationBuilders.filter(
                                                                "reworkSuccessCount",
                                                                QueryBuilders.boolQuery()
                                                                        .must(QueryBuilders.termQuery("type", OrderConsts.ORDER_TYPE_REWORK))
                                                                        .must(QueryBuilders.existsQuery("completeTime"))
                                                                        // （订单收入）> 50
                                                                        .filter(QueryBuilders.scriptQuery(new Script(ScriptType.INLINE, "painless", "doc['totalAmount'].value  >= 5000", Maps.newHashMapWithExpectedSize(0)))))

                                                )
                                                .subAggregation(
                                                        // 新单成功 + 返修成功：新单、返修单中，有完成时间，（订单收入）>= 50 或开票金额>=50；并且结果是：成功，不含重复
                                                        AggregationBuilders.filter(
                                                                "successOrderCount",
                                                                QueryBuilders.boolQuery()
                                                                        .must(QueryBuilders.termQuery("resultStatus", OrderStatusConsts.WORK_RESULT_SUCCESS))
                                                                        .must(QueryBuilders.existsQuery("completeTime"))
                                                                        .filter(QueryBuilders.scriptQuery(new Script(ScriptType.INLINE, "painless", " doc['totalAmount'].value >= 5000 || doc['billAmount'].value >= 5000", Maps.newHashMapWithExpectedSize(0)))))

                                                )

                                )
                                .subAggregation(
                                        AggregationBuilders.filter("accountTimeFilter", QueryBuilders.rangeQuery("accountTime").from(beginTime).to(endTime))
                                                .subAggregation(
                                                        // 订单收入
                                                        AggregationBuilders.sum("total_amount").field("totalAmount")
                                                )
                                                .subAggregation(
                                                        //配件销售总额
                                                        AggregationBuilders.sum("part_amount").field("partAmount")
                                                )
                                                .subAggregation(
                                                        AggregationBuilders.filter(
                                                                "depositAmount_filter",
                                                                QueryBuilders.boolQuery()
                                                                        .should(
                                                                                QueryBuilders.boolQuery()
                                                                                        .must(QueryBuilders.termQuery("depositPayType", PAY_TYPE_APP))
                                                                        )
                                                                        .should(QueryBuilders.boolQuery()
                                                                                .must(QueryBuilders.termQuery("depositChannelId", PAY_CHANNEL_PLATFORM_YIPAY))
                                                                        )

                                                        )
                                                                .subAggregation(
                                                                        AggregationBuilders.sum("userPayAmount").field("depositAmount")
                                                                )
                                                )
                                                // 用户现金支付总额 - 订单预收款支付
                                                .subAggregation(
                                                        AggregationBuilders.filter(
                                                                "prepayAmount_filter",
                                                                QueryBuilders.boolQuery()
                                                                        .should(
                                                                                QueryBuilders.boolQuery()
                                                                                        .must(QueryBuilders.termQuery("prepayPayType", PAY_TYPE_APP))
                                                                        )
                                                                        .should(QueryBuilders.boolQuery()
                                                                                .must(QueryBuilders.termQuery("prepayChannelId", PAY_CHANNEL_PLATFORM_YIPAY))
                                                                        )
                                                        )
                                                                .subAggregation(
                                                                        AggregationBuilders.sum("userPayAmount").field("prepayAmount")
                                                                )
                                                )
                                                // 用户现金支付总额 - 工程师收款支付
                                                .subAggregation(
                                                        AggregationBuilders.filter(
                                                                "masterAmount_filter",
                                                                QueryBuilders.boolQuery()
                                                                        .should(
                                                                                QueryBuilders.boolQuery()
                                                                                        .must(QueryBuilders.termQuery("payType", PAY_TYPE_APP))
                                                                        )
                                                                        .should(QueryBuilders.boolQuery()
                                                                                .must(QueryBuilders.termQuery("masterPayChannelId", PAY_CHANNEL_PLATFORM_YIPAY))
                                                                        )
                                                        )
                                                                .subAggregation(
                                                                        AggregationBuilders.sum("userPayAmount").field("masterAmount")
                                                                )
                                                )
                                )

                )
                .build();

        Aggregations query = orderWorkEsBService.getAggregationsByQuery(nativeSearchQuery);
        ParsedStringTerms companyCityTerms = query.get("companyId_cityId");
        List<? extends Terms.Bucket> buckets = companyCityTerms.getBuckets();

        List<PerfCity> perfCityList = Lists.newArrayList();
        if (!CollectionUtils.isEmpty(buckets)) {
            buckets.forEach(bucket -> {
                String keyAsString = bucket.getKeyAsString();
                String[] split = keyAsString.split("\\|");
                Aggregations aggregations = bucket.getAggregations();
                ParsedFilter receiveTimeFilter = aggregations.get("receiveTimeFilter");
                ParsedFilter accountTimeFilter = aggregations.get("accountTimeFilter");
                ParsedTopHits top = aggregations.get("top");
                Map<String, Aggregation> receiveTimeAggMap = receiveTimeFilter.getAggregations().asMap();
                Map<String, Aggregation> amountTimeAggMap = accountTimeFilter.getAggregations().asMap();
                PerfCity perfCity = new PerfCity();

                // 人工弃单数
                long discardCount = ((ParsedFilter) receiveTimeAggMap.get("discardCount")).getDocCount();
                perfCity.setDiscardCount((int) discardCount);

                // 系统弃单数
                long sysDiscardCount = ((ParsedFilter) receiveTimeAggMap.get("sysDiscardCount")).getDocCount();
                perfCity.setSysDiscardCount((int) sysDiscardCount);

                // 已上门失败数
                long visitFailCount = ((ParsedFilter) receiveTimeAggMap.get("visitFailCount")).getDocCount();
                perfCity.setVisitFailCount((int) visitFailCount);

                // 未上门失败数
                long noVisitFailCount = ((ParsedFilter) receiveTimeAggMap.get("noVisitFailCount")).getDocCount();
                perfCity.setNoVisitFailCount((int) noVisitFailCount);

                // 返修单
                long reworkOrderCount = ((ParsedFilter) receiveTimeAggMap.get("reworkOrderCount")).getDocCount();
                perfCity.setReworkOrderCount((int) reworkOrderCount);

                // 返修成功
                long reworkSuccessCount = ((ParsedFilter) receiveTimeAggMap.get("reworkSuccessCount")).getDocCount();
                perfCity.setReworkSuccessCount((int) reworkSuccessCount);

                //  新单成功 + 返修成功
                long successOrderCount = ((ParsedFilter) receiveTimeAggMap.get("successOrderCount")).getDocCount();
                perfCity.setSuccessOrderCount((int) successOrderCount);

                // 新单数
                long newOrderCount = ((ParsedFilter) receiveTimeAggMap.get("newOrderCount")).getDocCount();
                perfCity.setNewOrderCount((int) newOrderCount);


                //配件销售总额
                ParsedSum aggregation = (ParsedSum) amountTimeAggMap.get("part_amount");
                perfCity.setPartAmount((int) aggregation.getValue());

                //订单收入
                ParsedSum totalAmount = (ParsedSum) amountTimeAggMap.get("total_amount");
                perfCity.setOrderAmount((int) totalAmount.getValue());

                int userPayAmount1 = (int) ((ParsedSum) ((ParsedFilter) amountTimeAggMap.get("depositAmount_filter")).getAggregations().get("userPayAmount")).getValue();
                int userPayAmount2 = (int) ((ParsedSum) ((ParsedFilter) amountTimeAggMap.get("prepayAmount_filter")).getAggregations().get("userPayAmount")).getValue();
                int userPayAmount3 = (int) ((ParsedSum) ((ParsedFilter) amountTimeAggMap.get("masterAmount_filter")).getAggregations().get("userPayAmount")).getValue();
                int userPayAmount = userPayAmount1 + userPayAmount2 + userPayAmount3;
                perfCity.setUserPayAmountSum(userPayAmount);
                // 设置公司名称、城市名称等信息
                SearchHit hit = top.getHits().getAt(0);
                Map<String, Object> source = hit.getSourceAsMap();
                perfCity.setCityId(Integer.valueOf(source.get("cityId").toString()));
                perfCity.setCompanyId(Integer.valueOf(source.get("companyId").toString()));
                perfCity.setCompanyName(source.get("companyName").toString());
                perfCity.setCityName(source.get("cityName").toString());
                perfCity.setManageCompanyId(Integer.valueOf(source.get("manageCompanyId").toString()));
                perfCity.setManageCompanyName(source.get("manageCompanyName").toString());
                perfCity.setCityName(source.get("cityName").toString());
                perfCity.setMonth(month);
                perfCityList.add(perfCity);
            });
        }
        return perfCityList;
    }


    /**
     * 描述: 报表导出
     *
     * @param query 条件
     * @return java.util.ArrayList<java.util.List>
     * @author wangjie
     * @date 16:50 2019/3/2
     **/
    @SuppressWarnings("AlibabaRemoveCommentedCode")
    @Override
    public ExportExcelBuilder outputExcel(PerfCityQuery query) {
        query.setPageIndex(1);
        ExportExcelBuilder exportExcelBuilder = new ExportExcelBuilder();
        List<PerfCity> perfCitys = this.perfCityService.listPerfCity(query);
        if (CollectionUtils.isEmpty(perfCitys)) {
            return exportExcelBuilder;
        }
        Map<String, String> fields = Maps.newLinkedHashMap();
        fields.put("companyName", "子公司");
        fields.put("manageCompanyName", "服务公司");
        fields.put("cityName", "城市");
        fields.put("AbandonmentRateCallback", "弃单率");
        fields.put("discardCount", "人工弃单");
        fields.put("newOrderCount", "新单");
        fields.put("SystemAbandonmentRateCallback", "系统弃单率");
        fields.put("sysDiscardCount", "系统弃单");
        fields.put("newOrderCount2", "新单");
        fields.put("HomeFailureRateCallback", "上门失败率");
        fields.put("visitFailCount", "已上门失败");
        fields.put("newOrderCount3", "新单");
        fields.put("UnsuccessfulHomeFailureRateCallback", "未上门失败率");
        fields.put("noVisitFailCount", "未上门失败");
        fields.put("newOrderCount4", "新单");
        fields.put("RepairRateCallback", "返修率");
        fields.put("reworkOrderCount", "返修单");
        fields.put("newOrderCount5", "新单");
        fields.put("RebateSuccessRatioCallback", "返修成功占比");
        fields.put("reworkSuccessCount", "返修成功");
        fields.put("reworkOrderCount2", "返修单");
        fields.put("AccessibilityRateCallback", "配件率");
        fields.put("PartAmountCallback", "配件金额");
        fields.put("OrderAmountCallback", "订单收入");
        fields.put("SuccessRateCallback", "成功率");
        fields.put("SuccessfulNewOrderCallback", "新单成功");
        fields.put("reworkSuccessCount2", "返修成功");
        fields.put("newOrderCount6", "新单");
        fields.put("reworkOrderCount3", "返修单");


        fields.put("uesrPayAmountRateCallback", "用户现金支付");
        fields.put("userPayAmountSumCallback", "用户现金支付总额");
        fields.put("OrderAmountCallback2", "订单收入");
        ExportExcelBuilder.ExcelSheet<PerfCity> excelSheet = exportExcelBuilder.createExcelSheet("城市绩效-汇总", perfCitys, fields, false, true, 2);
        excelSheet.setCallback((fieldName, entity) -> {
            Integer newOrderCount = entity.getNewOrderCount();
            switch (fieldName) {
                case "AbandonmentRateCallback":
                    return MathUtil.mul(this.div(entity.getDiscardCount(), newOrderCount), 100) + "%";
                case "SystemAbandonmentRateCallback":
                    return MathUtil.mul(this.div(entity.getSysDiscardCount(), newOrderCount), 100) + "%";
                case "newOrderCount2":
                    return newOrderCount;
                case "HomeFailureRateCallback":
                    return MathUtil.mul(this.div(entity.getVisitFailCount(), newOrderCount), 100) + "%";
                case "newOrderCount3":
                    return newOrderCount;
                case "UnsuccessfulHomeFailureRateCallback":
                    return MathUtil.mul(this.div(entity.getNoVisitFailCount(), newOrderCount), 100) + "%";
                case "newOrderCount4":
                    return newOrderCount;
                case "RepairRateCallback":
                    return MathUtil.mul(this.div(entity.getReworkOrderCount(), (newOrderCount + entity.getReworkOrderCount())), 100) + "%";
                case "newOrderCount5":
                    return newOrderCount;
                case "RebateSuccessRatioCallback":
                    return MathUtil.mul(this.div(entity.getReworkSuccessCount(), entity.getReworkOrderCount()), 100) + "%";
                case "reworkOrderCount2":
                    return entity.getReworkOrderCount();
                case "AccessibilityRateCallback":
                    return MathUtil.mul(this.div(entity.getPartAmount(), entity.getOrderAmount()), 100) + "%";
                case "SuccessRateCallback":
                    return MathUtil.mul(this.div(entity.getSuccessOrderCount(), (newOrderCount + entity.getReworkOrderCount())), 100) + "%";
                case "SuccessfulNewOrderCallback":
                    return entity.getSuccessOrderCount() - entity.getReworkSuccessCount();
                case "reworkSuccessCount2":
                    return entity.getReworkSuccessCount();
                case "newOrderCount6":
                    return newOrderCount;
                case "reworkOrderCount3":
                    return entity.getReworkOrderCount();
                case "PartAmountCallback":
                    return MoneyUtil.parseToYuanStr(entity.getPartAmount());
                case "OrderAmountCallback":
                    return MoneyUtil.parseToYuanStr(entity.getOrderAmount());
                case "uesrPayAmountRateCallback":
                    return MathUtil.mul(this.div(entity.getUserPayAmountSum(), entity.getOrderAmount()), 100) + "%";
                case "userPayAmountSumCallback":
                    return MoneyUtil.parseToYuanStr(entity.getUserPayAmountSum());
                case "OrderAmountCallback2":
                    return MoneyUtil.parseToYuanStr(entity.getOrderAmount());
                default:
                    return "";
            }
        });
        excelSheet.builderData();
        //表头合并单元格相关
        excelSheet.addMergedRegion(0, 1, 0, 0);
        excelSheet.addMergedRegion(0, 1, 1, 1);
        excelSheet.addMergedRegion(0, 1, 2, 2);
        HSSFSheet sheet = excelSheet.getSheet();
        HSSFRow row = sheet.getRow(0);
        //复制表头到第二行
        for (int i = row.getFirstCellNum(); i < row.getLastCellNum(); i++) {
            String stringCellValue = row.getCell(i).getStringCellValue();
            //            row.getCell(i).setCellType(CellType.NUMERIC);
            excelSheet.setHSSFCellValue(1, i, stringCellValue);
        }
        //合并第一行表头
        for (int i = 3; i < 24; i += 3) {
            CellRangeAddress region = new CellRangeAddress(0, 0, i, i + 2);
            sheet.addMergedRegion(region);
        }
        //成功率四列单独合并
        CellRangeAddress region = new CellRangeAddress(0, 0, 24, 28);
        sheet.addMergedRegion(region);
        CellRangeAddress region2 = new CellRangeAddress(0, 0, 29, row.getLastCellNum() - 1);
        sheet.addMergedRegion(region2);
        return exportExcelBuilder;
    }

    @Override
    public PerfCityVO getTotalLine(PerfCityQuery query) {
        PerfCitySummary totalLine = this.perfCityService.findTotalLine(query);
        if (Objects.isNull(totalLine)) {
            return null;
        }
        totalLine.setManageCompanyName("总计");
        totalLine.setCityName("");
        return this.getPerfCityVOBySum(totalLine);
    }

    private PerfCityVO getPerfCityVOBySum(PerfCitySummary e) {
        if (Objects.isNull(e)) {
            return null;
        }
        PerfCityVO vo = new PerfCityVO();
        Long newOrderCount = e.getNewOrderCount();
        vo.setDiscardRate(this.div(e.getDiscardCount(), newOrderCount));
        vo.setSysDiscardRate(this.div(e.getSysDiscardCount(), newOrderCount));
        vo.setVisitFailRate(this.div(e.getVisitFailCount(), newOrderCount));
        vo.setNoVisitFailRate(this.div(e.getNoVisitFailCount(), newOrderCount));
        vo.setReworkRate(this.div(e.getReworkOrderCount(), (newOrderCount + e.getReworkOrderCount())));
        vo.setReworkSuccessRate(this.div(e.getReworkSuccessCount(), e.getReworkOrderCount()));
        vo.setPartRate(this.div(e.getPartAmount(), e.getOrderAmount()));
        vo.setCompleteRate(this.div(newOrderCount, e.getPlanOrderCount()));
        vo.setSuccessRate(this.div(e.getSuccessOrderCount(), (newOrderCount + e.getReworkOrderCount())));
        vo.setUserPayAmountRate(this.div(e.getUserPayAmountSum(), e.getOrderAmount()));
        vo.setCityName(e.getCityName());
        vo.setCompanyName(e.getCompanyName());
        vo.setManageCompanyName(e.getManageCompanyName());
        return vo;
    }


    /**
     * 描述: 提交保存城市绩效
     *
     * @param beginTime 开始时间，格式 yyyy-MM-dd hh:mm:ss
     * @param endTime   结束时间，格式 yyyy-MM-dd hh:mm:ss
     * @return boolean
     * @author wangjie
     * @date 14:38 2019/3/2
     **/
    @Override
    public boolean submitCity(String beginTime, String endTime) {

        List<PerfCity> perfCitys = this.queryStatisticsList(beginTime, endTime);
        if (!perfCitys.isEmpty()) {
            int month = Integer.parseInt(DateUtil.toString(beginTime, DateUtil.FORMAT_DEFAULT, DateUtil.FORMAT_MONTH2));
            perfCityService.deletcByMonth(month);

            if (perfCitys.size() > BASE_CROUP_NUM) {
                List<List<PerfCity>> partition = ListUtils.partition(perfCitys, 5);
                partition.forEach(e -> perfCityService.insertBatch(e));
            } else {
                perfCityService.insertBatch(perfCitys);
            }
        }
        return true;
    }

    /**
     * 描述: 根据条件加载数据(计算为PerfCityVo)
     *
     * @param query 查询条件
     * @return java.util.List<com.zmn.oms.model.vo.PerfCityVo>
     * @author wangjie
     * @date 15:32 2019/3/2
     **/
    @Override
    public List<PerfCityVO> listPageByQuery(PerfCityQuery query) {
        List<PerfCity> perfCitys = perfCityService.listPerfCity(query);
        return perfCitys.stream().map(this::getPerfCityVO).collect(Collectors.toList());
    }

    private PerfCityVO getPerfCityVO(PerfCity e) {
        if (Objects.isNull(e)) {
            return null;
        }
        PerfCityVO vo = new PerfCityVO();
        Integer newOrderCount = e.getNewOrderCount();
        vo.setDiscardRate(this.div(e.getDiscardCount(), newOrderCount));
        vo.setSysDiscardRate(this.div(e.getSysDiscardCount(), newOrderCount));
        vo.setVisitFailRate(this.div(e.getVisitFailCount(), newOrderCount));
        vo.setNoVisitFailRate(this.div(e.getNoVisitFailCount(), newOrderCount));
        vo.setReworkRate(this.div(e.getReworkOrderCount(), (newOrderCount + e.getReworkOrderCount())));
        vo.setReworkSuccessRate(this.div(e.getReworkSuccessCount(), e.getReworkOrderCount()));
        vo.setPartRate(this.div(e.getPartAmount(), e.getOrderAmount()));
        vo.setCompleteRate(this.div(newOrderCount, e.getPlanOrderCount()));
        vo.setSuccessRate(this.div(e.getSuccessOrderCount(), (newOrderCount + e.getReworkOrderCount())));
        vo.setUserPayAmountRate(this.div(e.getUserPayAmountSum(), e.getOrderAmount()));
        vo.setCityName(e.getCityName());
        vo.setCompanyName(e.getCompanyName());
        vo.setManageCompanyName(e.getManageCompanyName());
        return vo;
    }

    /**
     * 描述: 除法计算保留2位小数
     *
     * @param divisor  除数
     * @param dividend 被除数
     * @return java.lang.Double
     * @author wangjie
     * @date 15:55 2019/3/2
     **/
    private Double div(Integer divisor, Integer dividend) {

        divisor = Optional.ofNullable(divisor).orElse(GlobalConsts.NONE);
        dividend = Optional.ofNullable(dividend).orElse(GlobalConsts.NONE);

        if (Objects.equals(dividend, GlobalConsts.NONE)) {
            return 0.00;
        }
        return MathUtil.div(divisor, dividend, 4);
    }

    private Double div(Long divisor, Long dividend) {
        if (NumberUtil.isNullOrZero(divisor) || NumberUtil.isNullOrZero(dividend)) {
            return 0.00;
        }
        return new BigDecimal(divisor.toString()).divide(new BigDecimal(dividend.toString()), 4, BigDecimal.ROUND_HALF_UP).doubleValue();
    }
}
